package aimis.controller;

import aimis.constant.ResponseEnum;
import aimis.domain.Attachment;
import aimis.domain.Authority;
import aimis.domain.User;
import aimis.dto.PageQuery;
import aimis.dto.Result;
import aimis.dto.TableList;
import aimis.dto.form.LoginForm;
import aimis.dto.form.UserForm;
import aimis.repo.AttachmentRepo;
import aimis.repo.DepartmentRepo;
import aimis.repo.RoleRepo;
import aimis.repo.UserRepo;
import aimis.service.UserService;
import jakarta.validation.Valid;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RestController;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

@RestController
public class UserController {
    @Autowired
    private UserRepo userRepo;
    @Autowired
    private PasswordEncoder passwordEncoder;
    @Autowired
    private DepartmentRepo departmentRepo;
    @Autowired
    private RoleRepo roleRepo;
    @Autowired
    private UserService userService;
    @Value("${admin.role}")
    private String adminRole;
    @Autowired
    private AttachmentRepo attachmentRepo;

    @Value("${upload.tmp}")
    private String tmp;
    @Value("${upload.files}")
    private String filePath;
    @Value("${password.default}")
    private String defaultPassword;


    @PostMapping("/user/resetPassword")
    public Result resetPassword(@RequestBody @Validated(UserForm.ResetPassword.class) UserForm userForm) {
        var user = userRepo.findById(userForm.getId()).get();
        var encodedPassword = passwordEncoder.encode(defaultPassword);
        user.setPassword(encodedPassword);
        userRepo.save(user);
        return Result.success();
    }

    @PostMapping("/user/login")
    public Result login(@RequestBody @Valid LoginForm loginForm) {


        var user = userRepo.findByLoginName(loginForm.getLoginName());
        if (user != null && passwordEncoder.matches(loginForm.getPassword(), user.getPassword())) {
            String token = userService.genToken(user.getLoginName());
            return Result.success(ResponseEnum.OK)
                    .add("user", user)
                    .add("token", token)
                    .add("departmentId", user.getDepartment() != null ? user.getDepartment().getRoot().getId() : null)
                    .add("authorities", userService.getAuthorityNames(user));
        } else {
            return Result.error(ResponseEnum.LOGIN_FAIL);
        }
    }


    @PostMapping("/user/add")
    public Result add(@RequestBody @Validated(UserForm.AddUser.class) UserForm userForm) {
        User user = new User();
        BeanUtils.copyProperties(userForm, user);
        var encodedPassword = passwordEncoder.encode(user.getPassword());
        user.setPassword(encodedPassword);
        var department = departmentRepo.findById(userForm.getDepartmentId());
        user.setDepartment(department.get());

        for (var id : userForm.getRoleIds()) {
            var role = roleRepo.findById(id);
            user.getRoles().add(role.get());
        }

        Attachment avatarAttachment = userForm.getAvatarAttachment();
        if (avatarAttachment != null) {
            attachmentRepo.save(avatarAttachment);
            HashSet<Attachment> attachments = new HashSet<>();
            attachments.add(avatarAttachment);
            Attachment.moveTmpFile(attachments, tmp, filePath);
            user.setAvatar(avatarAttachment.getPath() + "?name=" + avatarAttachment.getFileName() + "&mineType=" + avatarAttachment.getMineType());
        }
        userRepo.save(user);
        return Result.success(ResponseEnum.OK);
    }

    @PostMapping("/user/edit")
    public Result edit(@RequestHeader(value = "token") String token, @RequestBody @Validated(UserForm.EditUser.class) UserForm userForm) {
//        User userLogin = userService.getUserFromToken(token);
        //Form对象-》Domain对象
        var findOne = userRepo.findById(userForm.getId());
        var user = findOne.get();
        var savedPassword = user.getPassword(); //保存原密码
        BeanUtils.copyProperties(userForm, user);
        if (user.getPassword() != null && !user.getPassword().isBlank()) {
            //前端给定密码时才修改，否保持原来的密码不变
            var encodedPassword = passwordEncoder.encode(user.getPassword());
            user.setPassword(encodedPassword);
        } else {
            user.setPassword(savedPassword);
        }

        user.getRoles().clear(); //清空角色
        var department = departmentRepo.findById(userForm.getDepartmentId());
        user.setDepartment(department.get());

        for (var id : userForm.getRoleIds()) {
            var role = roleRepo.findById(id);
            user.getRoles().add(role.get());
        }
//            for (var r : userLogin.getRoles()) {
//                if (r.getName().equals(adminRole)) {
//                    // 登录用户是管理员才能设置部门和角色
//                    user.getRoles().clear(); //清空角色
//                    var department = departmentRepo.findById(userForm.getDepartmentId());
//                    if (department.isPresent()) {
//                        user.setDepartment(department.get());
//                    } else {
//                        return Result.error("修改用户失败").add("reason", "id=%s的部门不存在".formatted(userForm.getDepartmentId()));
//                    }
//
//                    for (var id : userForm.getRoleIds()) {
//                        var role = roleRepo.findById(id);
//                        if (role.isPresent()) {
//                            user.getRoles().add(role.get());
//                        } else {
//                            return Result.error("修改用户失败").add("reason", "id=%s的角色不存在".formatted(id));
//                        }
//                    }
//                    break;
//                }
//            }
        Attachment avatarAttachment = userForm.getAvatarAttachment();
        if (avatarAttachment != null) {
            attachmentRepo.save(avatarAttachment);
            HashSet<Attachment> attachments = new HashSet<>();
            attachments.add(avatarAttachment);
            Attachment.moveTmpFile(attachments, tmp, filePath);
            user.setAvatar(avatarAttachment.getPath() + "?name=" + avatarAttachment.getFileName() + "&mineType=" + avatarAttachment.getMineType());
        }
        userRepo.save(user);
        return Result.success(ResponseEnum.OK);

    }

    @PostMapping("/user/getByToken")
    public Result getByToken(String token) {
        var user = userService.getUserFromToken(token);
        if (user != null) {
            return Result.success(ResponseEnum.OK).add("user", user);
        } else {
            return Result.error(ResponseEnum.DATA_NOT_EXIST);
        }
    }

    @PostMapping("/user/getById")
    public Result getById(Long id) {
        var user = userRepo.findById(id);
        if (user.isPresent()) {
            return Result.success(ResponseEnum.OK).add("user", user);
        } else {
            return Result.error(ResponseEnum.DATA_NOT_EXIST);
        }
    }

    @PostMapping("/user/delete")
    public Result delete(@RequestBody @Validated(UserForm.DeleteUser.class) UserForm userForm) {
        userRepo.deleteById(userForm.getId());
        return Result.success(ResponseEnum.OK);
    }

    @PostMapping(value = "/user/findByQuery")
    public TableList<User> findByQuery(@RequestHeader(value = "token") String token, String name, @RequestHeader(value = "departmentId") Long departmentId, PageQuery pageQuery) {
        var pageable = pageQuery.toPageable();
        if (name != null && name.isBlank())
            name = null;
        User user = userService.getUserFromToken(token);
        var root = departmentRepo.findById(departmentId).get().getRoot();
        if (root.getAccessAllDepartment()) {
            var users = userRepo.findByQuery(name, pageable);
            return TableList.create(users);
        } else {
            var users = userRepo.findByQuery(name, root, pageable);
            return TableList.create(users);
        }
//        for (var r : user.getRoles()) {
//            if (r.getName().equals(adminRole)) {
//                var root = departmentRepo.findById(departmentId).get().getRoot();
//                if (root.getAccessAllDepartment()) {
//                    var users = userRepo.findByQuery(name, pageable);
//                    return TableList.create(users);
//                } else {
//                    var users = userRepo.findByQuery(name, root, pageable);
//                    return TableList.create(users);
//                }
//            }
//        }
//        // 非管理员拿自己
//        PageImpl<User> users = new PageImpl<>(List.of(user), pageable, 1);
//        return TableList.create(users);
    }

    @PostMapping(value = "/user/findByQueryAndDepartment")
    public TableList<User> findByQueryAndDepartment(String name, @RequestHeader(value = "departmentId") Long departmentId, PageQuery pageQuery, long queryDepartmentId) {
        var pageable = pageQuery.toPageable();
        if (name != null && name.isBlank())
            name = null;
        var root = departmentRepo.findById(queryDepartmentId).get().getRoot();
        var users = userRepo.findByQuery(name, root, pageable);
        return TableList.create(users);
    }


    @PostMapping(value = "/user/findAll")
    public List<User> findAll(@RequestHeader(value = "departmentId") Long departmentId) {
        var root = departmentRepo.findById(departmentId).get().getRoot();
        if (root.getAccessAllDepartment()) {
            return userRepo.findAll();
        } else {
            return userRepo.findAll(root);
        }

    }

    @PostMapping(value = "/user/updatePassword")
    public Result updatePassword(String oldPassword, String newPassword, Long id) {
        var user = userRepo.findById(id).get();
        if (passwordEncoder.matches(oldPassword, user.getPassword())) {
            user.setPassword(passwordEncoder.encode(newPassword));
            userRepo.save(user);
            return Result.success(ResponseEnum.OK);
        } else {
            return Result.error(ResponseEnum.PASSWORD_NOT_MATCH);
        }
    }

    @PostMapping(value = "/user/findAllByAuthorities")
    public List<User> findByAuthorities(@RequestBody Set<String> rights, @RequestHeader(value = "departmentId") Long departmentId) {
        Set<Authority> authorities = new HashSet<>();
        for (var a : rights) {
            authorities.add(new Authority(a));
        }
        var root = departmentRepo.findById(departmentId).get().getRoot();
        List<User> all = userRepo.findAll(root);
        List<User> userResult = new ArrayList<>();

        for (var u : all) {
            for (var r : u.getRoles()) {
                if (r.getAuthorities().containsAll(authorities)) {
                    userResult.add(u);
                }
            }
        }
        return userResult;
    }

//    @RequestMapping(value = "/user/getAuthorities", method = RequestMethod.GET)
//    public Set<Authority> getAuthorities(Long id) {
//        Set<Authority> authorities = new HashSet<>();
//        var user = userRepo.findById(id);
//        if (user.isPresent()) {
//            for (var role : user.get().getRoles()) {
//                for (var i : role.getAuthorities()) {
//                    authorities.add(i);
//                }
//            }
//        }
//        return authorities;
//    }
}
